// Learn TypeScript:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:

import MsgMgr from "../event/MsgMgr";
import { nProxy } from "./Decorator";

//  - https://docs.cocos.com/creator/2.4/manual/en/scripting/life-cycle-callbacks.html
export const PROXY_IS_INIT_PROXY = "proxy:is_init_proxy"
export const PROXY_INIT_PROXY_FUNC = "proxy:init_proxy"
export const PROXY_ATTR_PATH = "proxy:attr_path"

const dispatcher = (path:string, attrName, oldVal, newVal) =>{
    //console.error("属性路径:"+path+"/"+attrName+" 旧的数据:"+oldVal+" 新的数据:"+newVal);
    MsgMgr.emit(path, attrName, oldVal, newVal);
}

const initProxy = (target:any)=>{
    if (!target[PROXY_IS_INIT_PROXY]) {
        target[PROXY_INIT_PROXY_FUNC] && target[PROXY_INIT_PROXY_FUNC](target)
    }
}

const dealDispatcherPath = (target:any, prop:string)=>{
    if (Array.isArray(target)) {
        return target[PROXY_ATTR_PATH]
    }else {
        return `${target[PROXY_ATTR_PATH]}/${prop}`
    }
}

const dealDispatcherProp = (target:any, prop:string)=>{
    if (Array.isArray(target)) {
        let temp = target[PROXY_ATTR_PATH].split("/");
        return temp[temp.length-1]+"/"+prop;
    }else {
        return prop
    }
}

const dealNewVal = (oldVal, newVal)=>{
    if (Array.isArray(oldVal) && Array.isArray(newVal)) {//直接替换整个数组 需要对新的数组进行代理
        newVal[PROXY_ATTR_PATH] = oldVal[PROXY_ATTR_PATH];
        newVal = proxy(newVal);
        return newVal;
    }else {
        return newVal;
    }
}

export const proxy = (object:any, parent?:any)=>{
    return new Proxy(object, {
        get(target:any, prop:string, receiver) {
            initProxy(target);
            return Reflect.get(target, prop, receiver);
        },
        set(target:any, prop:string, val, receiver) {
            initProxy(target);
            let oldVal = target[prop];
            let path = dealDispatcherPath(target, prop);
            prop = dealDispatcherProp(target, prop);
            val = dealNewVal(oldVal, val);
            let ret = Reflect.set(target, prop, val, receiver);
            dispatcher(path, prop, oldVal, val);
            return ret;
        }
    })
}

